/**
  ******************************************************************************
  * @file    EEPROM_Emul/Porting/STM32L4/flash_interface.c
  * @author  MCD Application Team
  * @brief   This file provides all the EEPROM emulation flash interface functions.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "eeprom_emul.h"
#include "flash_interface.h"
/** @addtogroup EEPROM_Emulation
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
#if defined(FLASH_BANK_2)
static uint32_t GetBankNumber(uint32_t Address);
#endif

/* Exported functions --------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
  * @{
  */
#define FLASH_ERASE_GUARD_TIME   (10240U)    // 25 ms
#define FLASH_WRITE_GUARD_TIME   (500U)  // 1 ms

#define WITH_RADIO_MUTEX	

#define ATOMIC_SECTION_BEGIN() uint32_t uwPRIMASK_Bit = __get_PRIMASK(); \
__disable_irq(); \
  /* Must be called in the same or in a lower scope of ATOMIC_SECTION_BEGIN */
#define ATOMIC_SECTION_END() __set_PRIMASK(uwPRIMASK_Bit)

/**
  * @brief  Write a double word at the given address in Flash
  * @param  Address Where to write
  * @param  Data What to write
  * @retval EE_Status
  *           - EE_OK: on success
  *           - EE_WRITE_ERROR: if an error occurs
  */
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data)
{
	HAL_StatusTypeDef status;
#ifdef WITH_RADIO_MUTEX
	uint8_t NVMDB_TimeCheck(int32_t time);
	while(1){
		uint8_t ret = NVMDB_TimeCheck(FLASH_WRITE_GUARD_TIME);
		if(ret == TRUE){
			ATOMIC_SECTION_BEGIN();
#endif			
			status = HAL_FLASH_Program(Address, Data);
			status |= HAL_FLASH_Program(Address+4, Data>>32);
#ifdef WITH_RADIO_MUTEX			
			ATOMIC_SECTION_END();
			break;
		}else{
		    //printf("busy to write \r\n");
		}
	}
#endif
  return status;
}

/**
  * @brief  Erase a page in polling mode
  * @param  Page Page number
  * @param  NbPages Number of pages to erase
  * @retval EE_Status
  *           - EE_OK: on success
  *           - EE error code: if an error occurs
  */
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages)
{
  EE_Status status = EE_OK;
  FLASH_EraseInitTypeDef s_eraseinit;
  uint32_t page_error = 0U;
  
  s_eraseinit.TypeErase   = LL_FLASH_TYPE_ERASE_PAGES;
  s_eraseinit.NbPages     = NbPages;
  s_eraseinit.Page        = Page;

#ifdef WITH_RADIO_MUTEX
	uint8_t NVMDB_TimeCheck(int32_t time);
	while(1){
		uint8_t ret = NVMDB_TimeCheck(FLASH_ERASE_GUARD_TIME);
		if(ret == TRUE){
			ATOMIC_SECTION_BEGIN();
#endif
			/* Erase the Page: Set Page status to ERASED status */
			if (HAL_FLASHEx_Erase(&s_eraseinit, &page_error) != HAL_OK)
			{
				status = EE_ERASE_ERROR;
			}
#ifdef WITH_RADIO_MUTEX
			ATOMIC_SECTION_END();
			break;
		}
		else{
				//printf("busy to HAL_FLASHEx_Erase \r\n");
		}
	}
#endif
  return status;
}

#if 0
/**
  * @brief  Erase a page with interrupt enabled
  * @param  Page Page number
  * @param  NbPages Number of pages to erase
  * @retval EE_Status
  *           - EE_OK: on success
  *           - EE error code: if an error occurs
  */
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages)
{
  EE_Status status = EE_OK;
  FLASH_EraseInitTypeDef s_eraseinit;
  
#ifdef FLASH_BANK_2
  uint32_t bank = GetBankNumber(PAGE_ADDRESS(Page));
  s_eraseinit.Banks       = bank;
#endif
  
  s_eraseinit.TypeErase   = LL_FLASH_TYPE_ERASE_PAGES;
  s_eraseinit.NbPages     = NbPages;
  s_eraseinit.Page        = Page;

  /* Erase the Page: Set Page status to ERASED status */
  if (HAL_FLASHEx_Erase_IT(&s_eraseinit) != HAL_OK)
  {
    status = EE_ERASE_ERROR;
  }
  return status;
}
#endif
/**
  * @brief  Flush the caches if needed to keep coherency when the flash content is modified
  */
void FI_CacheFlush()
{
  /* No flush needed. There is no D-Cache for the BlueNRG-LPx products. */
  return;
}

#if defined(FLASH_BANK_2)
/**
  * @brief  Gets the bank of a given address
  * @param  Address Address of the FLASH Memory
  * @retval Bank_Number The bank of a given address
  */
static uint32_t GetBankNumber(uint32_t Address)
{
  uint32_t bank = 0U;

  if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0U)
  {
    /* No Bank swap */
    if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
    {
      bank = FLASH_BANK_1;
    }
    else
    {
      bank = FLASH_BANK_2;
    }
  }
  else
  {
    /* Bank swap */
    if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
    {
      bank = FLASH_BANK_2;
    }
    else
    {
      bank = FLASH_BANK_1;
    }
  }

  return bank;
}
#endif

/**
  * @brief  Delete corrupted Flash address, can be called from NMI. No Timeout.
  * @param  Address Address of the FLASH Memory to delete
  * @retval EE_Status
  *           - EE_OK: on success
  *           - EE error code: if an error occurs
  */
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address)
{
  EE_Status status = EE_OK;

//  /* Set FLASH Programmation bit */
//  SET_BIT(FLASH->CR, FLASH_CR_PG);
    
  /* Program double word of value 0 */
  *(__IO uint32_t*)(Address) = (uint32_t)0U;
  *(__IO uint32_t*)(Address+4U) = (uint32_t)0U;

  /* Wait programmation completion */
  while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_CMDDONE) == SET) ;

  /* Check flash errors */
  if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_ALL_ERRORS)) 
  {
    /* Save the error code */
    pFlash.ErrorCode |= FLASH->IRQSTAT;

    /* Clear error flags */
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);

    status = EE_DELETE_ERROR;
  }
	return status;
}

/**
  * @brief  Check if the configuration is 128-bits bank or 2*64-bits bank
  * @param  None
  * @retval EE_Status
  *           - EE_OK: on success
  *           - EE error code: if an error occurs
  */
EE_Status FI_CheckBankConfig(void)
{
#if defined (FLASH_DBANK_SUPPORT)
  EE_Status status;

  /* Check the value of the DBANK user option byte */
  if (OB_USER_DUALBANK_ENABLE)
  {
    status = EE_OK;
  }
  else
  {
    status = EE_INVALID_BANK_CFG;
  }

  return status;
#else
  /* No feature 128-bits single bank, so always 64-bits dual bank */
  return EE_OK;
#endif
}


/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
